package com.wuzihao.maze.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Date;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

import com.wuzihao.maze.constant.BlockStatus;
import com.wuzihao.maze.service.impl.DFSGenerateStrategy;
import com.wuzihao.maze.service.impl.DFSSearchStrategy;
import com.wuzihao.maze.service.GenerateMazeStrategy;
import com.wuzihao.maze.service.SearchPathStrategy;

public class MazePanel extends JPanel implements ActionListener {

	private static final long serialVersionUID = 1L;

	public static final int SIZE = 15;// 障碍物的大小
	private final int TIME = 20;// 定时时间
	private int n;// 计数器

	private int mazeSize; // 迷宫大小

	private int startX;
	private int startY;

	private long startTime;
	/** 寻找路径所耗费的时间 */
	private long usedTime;

	private Timer timer;

	private GenerateMazeStrategy generateMazeStrategy;
	private int[][] maze;
	private SearchPathStrategy searchPathStrategy;

	private Point[] locations;
	public MazePanel(int mazeSize) {
		init(mazeSize);
		addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				int key = e.getKeyCode();
				keyHandle(key);
			}
		});
	}

	private void init(int mazeSize) {
		if (mazeSize < 40) {
			this.mazeSize = 41;
		}
		this.mazeSize = mazeSize;
		setSize(mazeSize * SIZE, mazeSize * SIZE);
		timer = new Timer(TIME, this);
		generateMazeStrategy = new DFSGenerateStrategy();
		searchPathStrategy = new DFSSearchStrategy();
		startX = 1;
		startY = 1;
	}

	// build maze map
	public void buildMaze() {
		maze = null;
		locations = null;
		n = 0;
		startX = 1;
		startY = 1;
		usedTime = 0;

		timer.stop();
		maze = generateMazeStrategy.generate(mazeSize);
		startTime = System.currentTimeMillis();
	}

	// search maze path
	public void searchPath() {
		timer.start();
		n = 0;
		if (locations == null || locations.length == 0) {
			locations = searchPathStrategy.search(maze);
			System.out.println(locations.toString());
		}
	}

	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (maze != null && maze.length > 0) {// draw maze map
			g.clearRect(0, 0, mazeSize * SIZE, mazeSize * SIZE);
			for (int i = 0; i < mazeSize; i++) {
				for (int j = 0; j < mazeSize; j++) {
					if (maze[i][j] == BlockStatus.INIT) {
						g.fill3DRect(0 + SIZE * i, 0 + SIZE * j, SIZE, SIZE, true);
					}
				}
			}

			g.setColor(Color.GREEN);
			g.fill3DRect(SIZE * 1, SIZE * 1, SIZE, SIZE, true);// 入口
			g.fill3DRect(SIZE * (mazeSize - 2), SIZE * (mazeSize - 2), SIZE, SIZE, true);// 出口
			g.fill3DRect(SIZE * startX, SIZE * startY, SIZE, SIZE, true);// 行走
		}

		g.setColor(Color.GREEN);
		if (locations != null && locations.length > 0) {
			for (int i = 0; i < n; i++) {
				g.fill3DRect(SIZE * locations[i].x, SIZE * locations[i].y, SIZE, SIZE, true);
			}
		}
	}

	public int getRow() {
		return mazeSize;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == timer) {
			n++;
			repaint();
			if (n >= locations.length) {
				timer.stop();
			}
		}
	}

	// 判断是否到达出口
	private void isExit() {
		if (startX == mazeSize - 2 && startY == mazeSize - 2) {
			usedTime = (System.currentTimeMillis() - startTime) / 1000;
			int option = JOptionPane.showConfirmDialog(null, "是否继续？", "恭喜你找到出口！", JOptionPane.YES_NO_OPTION);
			if (option == JOptionPane.YES_OPTION) {
				buildMaze();
				repaint();
			} else {
				System.exit(0);
			}
		}
	}

	private void keyHandle(int key) {
		if (key == KeyEvent.VK_UP) {
			startY--;
			if (maze[startX][startY] == BlockStatus.OPEN) {// 判断是否碰到墙
				repaint();
				isExit();
			} else {
				startY++;
			}
		} else if (key == KeyEvent.VK_RIGHT) {
			startX++;
			if (maze[startX][startY] == BlockStatus.OPEN) {
				repaint();
				isExit();
			} else {
				startX--;
			}
		} else if (key == KeyEvent.VK_DOWN) {
			startY++;
			if (maze[startX][startY] == BlockStatus.OPEN) {
				repaint();
				isExit();
			} else {
				startY--;
			}
		} else if (key == KeyEvent.VK_LEFT) {
			startX--;
			if (maze[startX][startY] == BlockStatus.OPEN) {
				repaint();
				isExit();
			} else {
				startX++;
			}
		}
	}

	public long getUsedTime() {
		return usedTime;
	}

}
